#include "common.h"

#include <dirent.h>
#include <errno.h>
#include <sys/statvfs.h>

/* 1：app运行，0：app停止 */
static int app_running_flag = 1;

int is_app_running(void)
{
    return app_running_flag;
}

/**
 * @brief 设置app是否运行
 * @param running 1：app运行，0：app停止
*/
void set_app_running(int running)
{
    app_running_flag = running;
}

/**
  * @brief  检查文件是否存在
  * @param  null
  * @retval 0表示存在。-1表示不存在
  */
int file_exist(const char *file_dir)
{
    if (access(file_dir, F_OK) != -1) {
        // file exists
        //printf("%s exists \r\n", file_dir);
        return 0;
    } else {
        // file doesn't exist
        //printf("%s doesn't exist \r\n", file_dir);
        return -1;
    }
}

/**
  * @brief  创建文件夹
  * @param  null
  * @retval 0表示成功。-1表示失败
  */
int creat_dir(const char *path)
{
    char dir_name[256];
    strcpy(dir_name, path);
    int i, len = strlen(dir_name);

    for (i = 1; i < len; i++) {
        if (dir_name[i] == '/') {
            dir_name[i] = 0;

            if (access(dir_name, F_OK) != 0) {
                if (mkdir(dir_name, 0755) == -1) {
                    printf("mkdir %s error \r\n", path);
                    return -1;
                }
            }

            dir_name[i] = '/';

        }
    }

    return 0;
}

char *read_file(const char *filename)
{
    FILE *fp = NULL;
    int length = 0;
    char *content = NULL;
    size_t read_chars = 0;

    /* open in read binary mode */
    fp = fopen(filename, "rb");

    if (fp == NULL) {
        goto cleanup;
    }

    /* get the length */
    if (fseek(fp, 0, SEEK_END) != 0) {
        goto cleanup;
    }

    length = ftell(fp);

    if (length < 0) {
        goto cleanup;
    }

    if (fseek(fp, 0, SEEK_SET) != 0) {
        goto cleanup;
    }

    /* allocate content buffer */
    content = (char *)malloc((size_t)length + sizeof(""));

    if (content == NULL) {
        goto cleanup;
    }

    /* read the file into memory */
    read_chars = fread(content, sizeof(char), (size_t)length, fp);

    if ((int)read_chars != length) {
        free(content);
        content = NULL;
        goto cleanup;
    }

    content[read_chars] = '\0';

cleanup:

    if (fp != NULL) {
        fclose(fp);
    }

    return content;
}

int write_file(const char *filename, const char *buf)
{
    FILE *fp = NULL;

    if ((fp = fopen(filename, "w+")) != NULL) {
        fwrite(buf, strlen(buf), 1, fp);
        fclose(fp);
    } else {
        return -1;
    }

    return 0;
}

void sleep_ms(unsigned int ms)
{
    usleep(ms * 1000);
}

void sleep_s(unsigned int s)
{
    sleep(s);
}

const char *get_compiled_date_yyyy_mm_dd(void)
{
    // __DATE__ result: Apr 23 2020
    static char date_origin_format_buf[11] = {0};   // store __DATE__ chars
    int month = 0;               // store month number
    int i = 0;
    if (date_origin_format_buf[0] == 0) {          // can delete
        static const char *static_month_buf[] = {
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
        const char *cp_date = __DATE__;   // get origin format :month date year
        // store year to start of date_origin_format_buf
        memcpy(date_origin_format_buf, cp_date + 7, 4);
        // store date to start of date_origin_format_buf, but decade is ' ' when day little than 10
        // memcpy(date_origin_format_buf + 6, cp_date + 4, 2);
        for(i = 0; i < 12; i++) {
            // When static_month_buf[i] and cp_date store the same value in memory, month is i+1.
            if(memcmp(static_month_buf[i], cp_date, 3) == 0) {
                month = i+1;
                //printf("%d\n", month);
                break;
            }
        }
        date_origin_format_buf[4] = '-';
        date_origin_format_buf[5] = month / 10 % 10 + '0';
        date_origin_format_buf[6] = month % 10 + '0';
        date_origin_format_buf[7] = '-';
        // judge day is little than 10
        if (cp_date[4] == ' ') {
            date_origin_format_buf[8] = '0';
        } else {
            date_origin_format_buf[8] = cp_date[4];
        }
        date_origin_format_buf[9] = cp_date[5];
    }
    return date_origin_format_buf;
}


const char *get_compiled_date_yyyymmdd(void)
{
    
    static char date_origin_format_buf[9] = {0};   // store __DATE__ chars
    int month = 0;               // store month number
    int i = 0;
    if (date_origin_format_buf[0] == 0) {          // can delete
        static const char *static_month_buf[] = {
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
        const char *cp_date = __DATE__;   // get origin format :month date year
        // store year to start of date_origin_format_buf
        memcpy(date_origin_format_buf, cp_date + 7, 4);
        // store date to start of date_origin_format_buf, but decade is ' ' when day little than 10
        // memcpy(date_origin_format_buf + 6, cp_date + 4, 2);
        for(i = 0; i < 12; i++) {
            // When static_month_buf[i] and cp_date store the same value in memory, month is i+1.
            if(memcmp(static_month_buf[i], cp_date, 3) == 0) {
                month = i+1;
                break;
            }
        }
        date_origin_format_buf[4] = month / 10 % 10 + '0';
        date_origin_format_buf[5] = month % 10 + '0';
        // judge day is little than 10
        if (cp_date[4] == ' ') {
            date_origin_format_buf[6] = '0';
        } else {
            date_origin_format_buf[6] = cp_date[4];
        }
        date_origin_format_buf[7] = cp_date[5];
    }
    return date_origin_format_buf;
}

long long get_system_time_ms(void)
{
    long long time_ms;

    struct timeval tv;
    gettimeofday(&tv, NULL);
    time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;

    return time_ms;
}

int system_minute(void)
{
    time_t t = time(NULL);
    struct tm *t1 = localtime(&t);

    return t1->tm_min;
}

int char_to_int(char *ch)
{
    if (ch) {
        return atoi(ch);
    }

    return 0;
}

void int_to_char(int value, char *ch)
{
    sprintf(ch, "%d", value);
    //itoa(value, ch, 10);
}

float char_to_float(char *ch)
{
    if (ch) {
        return atof(ch);
    }

    return 0.0f;
}

int str_is_digit(char *p_str)
{
    int rtn = 0;

    if (NULL == p_str) return -1;

    if (strspn(p_str, "0123456789") == strlen(p_str)) {
        /* 全数字 */
        rtn = 1;
    }

    return rtn;
}

int strcmpnum(char *s, char *t)
{
    if (strlen(s) == strlen(t)) {
        return strcmp(s , t);
    } else {
        return strlen(s) - strlen(t);
    }
}

/**
 * @brief 设置app是否运行
 * @param src 源字符串的首地址(buf的地址)
 * @param separator 指定的分割字符
 * @param dest 接收子字符串的数组
 * @param num 分割后子字符串的个数
*/
void split(char *src, const char *separator, char **dest, int *num)
{
    char *pNext;
    int count = 0;

    if (src == NULL || strlen(src) == 0)
        return;

    if (separator == NULL || strlen(separator) == 0)
        return;

    pNext = (char *)strtok(src, separator);/* cast to char* */

    while (pNext != NULL) {
        *dest++ = pNext;
        ++count;
        pNext = (char *)strtok(NULL, separator);
    }

    *num = count;
}

/**
 * @brief 把设备标识分割成模型名称和guid
 * @param input 指定的分割字符
 * @param model 分割出来的模型名
 * @param guid 分割出来的guid
*/
void split_dev_string(const char *input, char *model, char *guid)
{
    // Find the last occurrence of '_'
    char *last_underscore = strrchr(input, '_');

    if (last_underscore != NULL)
    {
        // Calculate the lengths of the parts
        size_t model_len = last_underscore - input;
        size_t guid_len = strlen(input) - model_len - 1; // Subtract 1 for the '_'

        // Copy the parts into model and guid
        strncpy(model, input, model_len);
        model[model_len] = '\0'; // Null-terminate the model string

        strncpy(guid, last_underscore + 1, guid_len);
        guid[guid_len] = '\0'; // Null-terminate the guid string
    }
    else
    {
        // If there is no '_', set model to the input and guid to an empty string
        strcpy(model, input);
        guid[0] = '\0';
    }
}

// Function to calculate the size of a file
off_t get_file_size(const char *filepath)
{
    struct stat statbuf;
    if (stat(filepath, &statbuf) != 0)
    {
        perror("stat");
        return 0;
    }
    return statbuf.st_size;
}

// Recursive function to calculate the total size of a directory
off_t get_directory_size(const char *dirpath)
{
    DIR *dir;
    struct dirent *entry;
    char path[1024];
    off_t total_size = 0;

    if ((dir = opendir(dirpath)) == NULL)
    {
        perror("opendir");
        return -1;
    }

    while ((entry = readdir(dir)) != NULL)
    {
        // Skip "." and ".."
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        snprintf(path, sizeof(path), "%s/%s", dirpath, entry->d_name);
        struct stat statbuf;
        if (lstat(path, &statbuf) != 0)
        {
            perror("lstat");
            closedir(dir);
            return -2;
        }

        if (S_ISDIR(statbuf.st_mode))
        {
            // Recursively calculate the size of subdirectories
            total_size += get_directory_size(path);
        }
        else
        {
            // Add the size of the file
            total_size += get_file_size(path);
        }
    }

    closedir(dir);

    return total_size;
}

off_t get_remaining_space_size(const char *dirpath)
{
    struct statvfs stat;

    // 调用 statvfs 函数
    if (statvfs(dirpath, &stat) != 0)
    {
        perror("statvfs");
        return -1;
    }

    // 计算剩余空间大小（以字节为单位）
    long available_bytes = stat.f_bavail * stat.f_frsize;

    return available_bytes;
}
